<?php

namespace app\index\model;

use think\Model;

class Audio extends Model
{
    public $toTypes = [
        'mp3'   => [
            ['Mp3'] ,
        ] ,
        'aac'   => [
            ['Aac'] ,
        ] ,
        'flac'  => [
            ['Flac'] ,
        ] ,
        'wav'   => [
            ['Wav'] ,
            ['Aac'] ,
            ['Mp3'] ,
            //['Vorbis'] ,?
            //['Flac'] ,?
        ] ,
        'ogg'   => [
            ['Vorbis'] ,
            ['Flac'] ,
        ] ,
        // 'amr'   => [
        //     ['Flac'] ,
        //     ['Wav'] ,
        //     ['Aac'] ,
        //     ['Mp3'] ,
        //     ['Vorbis'] ,
        // ] ,
    ] ;

    public $rootUrl = null ;
    public $tmp     = null ;
    public $fname   = null ;

    public $path    = [
        'ffmpeg.binaries'   => '/usr/local/bin/ffmpeg',
        'ffprobe.binaries'  => '/usr/local/bin/ffprobe',
        'timeout'           => 7200 ,    // The timeout for the underlying process
        'ffmpeg.threads'    => 4 ,       // The number of threads that FFMpeg should use
    ];

    public $info    = [] ;

    # 接口接收信息
    // 队列 下载dd音频
    // md5dd音频
    // 创建该dd音频信息缓存
    // 处理转换信息 修改该dd音频信息缓存
    // 修改该dd音频信息缓存

    # 计划任务 定期清理过期文件

    # 接口
    // 文件处理进度
    // 下载

    /* 
    status 0 等待处理
    status 1 正在处理
    status 2 已经处理
     */

    // 入口
    public function process ($data=[]){

        $this->rootUrl = dirname( dirname( dirname( dirname(__FILE__) ) ) )."/public/" ;

        try {

            // 创建信息
            $this->info($data);

            if ( $this->info['status']==1 ) {
                exception('任务进行中');
            }
            
            // if ( $this->info['status']==2 ) {
            //     exception('任务已处理完毕');
            // }

            // 转换
            $this->run($data);

        } catch (ValidateException $e) {
            // 这是进行验证异常捕获
            $this->log([ 'err' , $e->getError() ] );
            //return json($e->getError());
            return false ;

        } catch (\Exception $e) {
            // 这是进行异常捕获
            $this->log([ 'msg' , $e->getMessage() ] );
            //return json($e->getMessage());
            return false ;
        }

        return true ;
    }

    // 处理信息
    public function info ($data=null){

        $this->R();

        if ( is_array( $data ) ) {
            asort($data) ;
            // md5dd音频
            $md5    = $this->remd($data) ;
        }else{
            $md5    = $data ;
        }

        // 是否存在dd音频记录 不存在就记录
        $status = $this->redis->HEXISTS('info',$md5);
        if ( empty( $status ) ) {
            // 任务状态
            $status = [
                'status'    => 0 ,
                'code'      => 0 ,
                'status_msg'=> '任务创建成功' ,
            ] ;
            $this->redis->HSET('status',$md5,json_encode(
                $status,JSON_UNESCAPED_UNICODE
            ));
            // 记录信息
            $data   = array_merge($data,$status) ;
            $this->redis->HSET('info',$md5,json_encode(
                $data,JSON_UNESCAPED_UNICODE
            ));

            $this->info = $data ;
        }else{
            // 查看该任务 状态
            $this->info = json_decode( $this->redis->HGET('info',$md5) , true ) ;
        }
        return $this->info ;
    }

    // 转换
    public function run ($data=[]){

        $this->get_tmp( $data['file'] );

        // redis
        $this->R();
        // 创建对象
        $ffmpeg = \FFMpeg\FFMpeg::create($this->path);
        // 打开资源
        $audio  = $ffmpeg->open($data['file']);
        // md5dd音频
        $md5    = $this->remd($data) ;
        $id     = $data['item_id'] ;

        // 循环需要转换的类型
        $this->log($id.'| --开始dd音频转码--');
        foreach ( $data['totype'] as $key => $type ) {
            $type   = strtolower( $type ) ;

            if ( !empty( $data['vcode'][$type] ) ) {
                // 指定 编码扩展 编码 文件
                $this->log($id.'| 指定编码扩展-'.$data['vcode']);
                list($oname)  = $data['vcode'][$type] ;
            }

            // 是否支持该类型
            if ( !empty( $this->toTypes[$type][0] ) ) {
                list($oname)  = $this->toTypes[$type][0] ;

            }else{
                // 不支持该类型
                // 退出
                $this->log([$id.'| 记录跳过-不支持该类型 : '.$data['vname'].'.'.$type ]);
                continue;
            }

            if ( strtolower($data['vtype']) == $type ) {
                // 文件类型 和 转换到的文件类型相同 不转换
                $this->log([$id.'| 记录跳过-文件类型相同 : '.$type ]);

                // 记录文件地址
                $this->w_info( $data['file'] , $md5 , $data );

                continue;
            }
            // 开始转换类型
            $onames     = '\FFMpeg\Format\Audio\\'.$oname ;
            $format     = new $onames() ;

            $this->log($id.'| 格式 : '.$type.' -类型 : '.$oname.'-转换对象 : '.$onames);

            $redis  = $this->redis ;

            // 记录进度
            $format->on('progress', function ($audio, $format, $percentage) use($redis,$md5){
                $redis->HSET('status',$md5,json_encode(
                    [
                        'status'    => 1 ,
                        'code'      => $percentage ,
                        'status_msg'=> 'dd音频转换中...' ,
                    ],
                    JSON_UNESCAPED_UNICODE
                ));
            });

            // 生成目录 设置存放目录
            //$this->tmp  = $data['dir'] ; // 'Uploads/qwe/123/'
            $this->mkdir($this->tmp);

            // 保存
            $fileUrl    = $this->tmp.$this->fname.'.'.$type ;

            @$audio->save($format,$this->rootUrl.$fileUrl);

            // 记录文件地址
            $this->w_info($fileUrl,$md5,$data);
            $this->log($id.'| 类型 : '.$oname.' OK ');

        }

        // 通知队列
        $info   = json_decode( $this->redis->HGET('info',$md5) , true ) ;
        \think\Queue::push('crontab/Notice@fire', $info , 'notice') ;

        $this->log($id.'| 全部转换完成');

        return true ;
    }

    private $_ROOT  = null ;
    private function mkdir($savepath='') {
        if ( !$this->_ROOT ) {
            $this->_ROOT    = realpath(dirname(__file__).'/../../../public/').'/';
        }
        $dir = rtrim($this->_ROOT.$savepath,'/');
        if (is_dir($dir)) {
            return $dir ;
        }
        if (mkdir($dir, 0755, true)) {
            return $dir ;
        } else {
            $this->log("目录 {$savepath} 创建失败！");
            return false ;
        }
    }

    private function get_tmp( $img='' ){
        print_r( $img );
        $path       = explode('Uploads/',$img ) ;
        $imgAll     = end( $path ) ;

        $imgAllArr  = explode('/', $imgAll ) ;
        $imgNameExt = array_pop( $imgAllArr ) ;
        $imgPath    = implode('/', $imgAllArr );

        $path2      = explode('.', $imgNameExt ) ;
        $imgName    = reset( $path2 ) ;

        $this->tmp      = 'Uploads/'.$imgPath.'/' ;
        $this->fname    = $imgName ;
    }

    private function w_info($fileUrl,$md5,$data) {

        $this->R();
        // 任务进度
        $status = [
            'status'    => 2 ,
            'code'      => 100 ,
            'status_msg'=> '任务完成' ,
        ] ;
        $this->redis->HSET('status',$md5,json_encode(
            $status,JSON_UNESCAPED_UNICODE
        ));

        // 记录信息
        $files  = [] ;
        $info   = json_decode( $this->redis->HGET('info',$md5) , true ) ;
        if ( !empty( $info ) && !empty( $info['files'] ) ) {
            $files      =array_merge($files,$info['files']);
            array_push( $files , $fileUrl );
        }else{
            $files[]    = $fileUrl ;
        }
        $data['files']  = $files ;

        // 记录信息
        $this->redis->HSET('info',$md5,json_encode(
            array_merge($data,$status),JSON_UNESCAPED_UNICODE
        ));
    }

    public $redis   = null ;
    private function R() {
        if ( ! $this->redis) {
            $this->redis = \think\facade\Cache::store('redis')->handler();
            //\think\facade\Cache::store('default');
        }

        return $this->redis;
    }

    public function remd($data) {
        // asort($data) ;
        // $md5    = md5( json_encode($data) ) ;
        // return $md5 ;
        return $data['item_id'] ;
    }

    private function log($msg) {
        $this->R();
        if ( is_array( $msg ) ) {
            print_r($msg);
            $this->redis->LPUSH('log',json_encode($msg,JSON_UNESCAPED_UNICODE) );
        }else{
            print_r([$msg]);
            $this->redis->LPUSH('log',$msg );
        }
    }

}
